package com.myblog.services.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.myblog.Utils.BeanCopyUtils;
import com.myblog.Utils.RedisCache;
import com.myblog.domain.GlobalResponse;
import com.myblog.domain.Vo.*;
import com.myblog.domain.contants.GlobalConstants;
import com.myblog.domain.dto.AddArticleDto;
import com.myblog.domain.entity.Article;

import com.myblog.domain.entity.ArticleTag;
import com.myblog.domain.entity.Category;
import com.myblog.mapper.ArticleMapper;
import com.myblog.services.ArticleService;
import com.myblog.services.ArticleTagService;
import com.myblog.services.CategoryService;
import io.jsonwebtoken.lang.Strings;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * @author Administrator
 * @description 针对表【sg_article(文章表)】的数据库操作Service实现
 * @createDate 2022-09-27 09:23:36
 */

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper,Article>
implements ArticleService {
    @Resource
    RedisCache redisCache;
    @Resource
    ArticleTagService articleTagService;


    @Override
    public GlobalResponse<List<HotArticleVo>> getHotArticleList() {
        //不能是已删除的(已配置可以不用管)
        //取前十个
        //按照倒序排列
        //不能是草稿
//        Map<String, Integer> id_viewCount_Map = redisCache.getCacheMap(GlobalConstants.VIEWCOUNT_MAP_NAME);
//        使用redis来对viewCount进行操作，目前没思路
        LambdaQueryWrapper<Article> queryWrapper=new LambdaQueryWrapper<>();
        //1.不能是草稿
        //Article::getStatus相当于拿article实体类的该变量名来进行对比，比手写的该变量名更加安全
        //GlobalConstants.ARTICLE_STATUS_NORMAL：将0封装成常量调用，提升高代码的可维护性（改动一处，不需要处处改动）
        queryWrapper.eq(Article::getStatus, GlobalConstants.ARTICLE_STATUS_NORMAL);
        //desc降序 asc升序
        //倒叙排列
        queryWrapper.orderByDesc(Article::getViewCount);
        //用page类封装article，1->第一页，GlobalConstants.HOTARTICLE_NUMBE：将10封装成常量，表示只要前十个
        //这是为了实现只要前十个而采用的分页查询的形式
        //取前十个
        Page<Article> page=new Page<>(1,GlobalConstants.HOTARTICLE_NUMBER);
        page(page,queryWrapper);
        //查询
        List<Article> articleList=page.getRecords();
        //bean拷贝:用Article类返回的值太多了，根据需求分析，我们只需要用到文章id，文章标题,浏览量和排序即可，所以我们创建了一  个新的类HotArticleVo作为响应类，使用Bean拷贝的形式将Article类的该部分数据拷贝到HotArticleVo里即可，因为这是一个重复性的动作所以我们创建了BeanCopyUtils来封装该方法，下面我会继续列出。
        List<HotArticleVo> hotArticleVoList= BeanCopyUtils.copyBeanList(articleList,HotArticleVo.class);
        return GlobalResponse.ok(hotArticleVoList);
    }


    @Resource
    CategoryService categoryService;

    @Override
    public GlobalResponse<PageVo> getArticleList(Integer pageNumber, Integer pageSize, Long categoryId) {

        //查询条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 如果 有categoryId 就要 查询时要和传入的相同
        System.out.println("pageNumber"+pageNumber);
        System.out.println("pageSize"+pageSize);

        lambdaQueryWrapper.eq(Objects.nonNull(categoryId)&&categoryId>0 ,Article::getCategoryId,categoryId);
        // 状态是正式发布的
        lambdaQueryWrapper.eq(Article::getStatus,GlobalConstants.ARTICLE_STATUS_NORMAL);
        // 对isTop进行降序
        lambdaQueryWrapper.orderByDesc(Article::getIsTop);
        //分页查询
        Page<Article> page = new Page<>(pageNumber,pageSize);
        page(page,lambdaQueryWrapper);

        List<Article> articles = page.getRecords();
        //查询categoryName
        List<Article> collect = articles.stream()
                .map(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()))
                .collect(Collectors.toList());
        //articleId去查询articleName进行设置
//        for (Article article : articles) {
//            Category category = categoryService.getById(article.getCategoryId());
//            article.setCategoryName(category.getName());
//        }
        //用redis中的ViewCount来替代数据库中的
        List<Article> collect1 = collect.stream()
                .map(article -> article.setViewCount(((Integer) redisCache.getCacheMapValue(GlobalConstants.VIEWCOUNT_MAP_NAME, article.getId().toString())).longValue()))
                .collect(Collectors.toList());

        //封装查询结果
        List<ArticleVo> articleListVos = BeanCopyUtils.copyBeanList(collect1, ArticleVo.class);

        PageVo pageVo = new PageVo(articleListVos,page.getTotal());
        return GlobalResponse.ok(pageVo);
    }


    @Override
    public GlobalResponse<ArticleDetailVo> getArticle(Long id) {
        //根据id查询文章
        Article article = getById(id);
        //从redis中获取文章观看数
        Integer viewCount = redisCache.getCacheMapValue(GlobalConstants.VIEWCOUNT_MAP_NAME, id.toString());
        article.setViewCount(viewCount.longValue());
        //转换成VO
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        //根据分类id查询分类名
        Long categoryId = articleDetailVo.getCategoryId();
        Category category = categoryService.getById(categoryId);
        if(category!=null){
            articleDetailVo.setCategoryName(category.getName());
        }
        //封装响应返回
        return GlobalResponse.ok(articleDetailVo);
    }

    @Override
    public GlobalResponse<?> updateViewCount(Long id) {
        redisCache.incrementCacheMapValue(GlobalConstants.VIEWCOUNT_MAP_NAME,id.toString(),1);
        return GlobalResponse.ok();
    }

    @Override
    public GlobalResponse<?> newArticle(AddArticleDto articleDto) {
        //在数据库新增然后在article_tag标关联
        Article article = BeanCopyUtils.copyBean(articleDto, Article.class);
        save(article);

        List<Long> tagList = articleDto.getTags();
        List<ArticleTag> articleTag = tagList.stream()
                .map(tag -> new ArticleTag(article.getId(), tag))
                .collect(Collectors.toList());
        articleTagService.saveBatch(articleTag);
        return GlobalResponse.ok();
    }

    @Override
    public GlobalResponse<List<ArticleVo>> getArticleList(Integer pageNumber, Integer pageSize, String title, String summary) {
        LambdaQueryWrapper<Article> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(Strings.hasText(title),Article::getTitle,title);
        lambdaQueryWrapper.like(Strings.hasText(summary),Article::getSummary,summary);
        List<Article> list = list(lambdaQueryWrapper);
        List<ArticleVo> articleVos = BeanCopyUtils.copyBeanList(list, ArticleVo.class);
        return GlobalResponse.ok(articleVos);
    }

    @Override
    public GlobalResponse<List<ArticleTag>> AdminGetArticle(Long id) {
        //先查出来
        Article article = getById(id);
        //用redis中的viewCount来替换其中的article.viewCount
        Integer viewCount= redisCache.getCacheMapValue(GlobalConstants.VIEWCOUNT_MAP_NAME, Long.toString(id));
        article.setViewCount(Long.valueOf(viewCount));
        // 先拷贝然后从Article Tag中查出对应的tagList替换掉
        AdminArticleVo adminArticleVo = BeanCopyUtils.copyBean(article, AdminArticleVo.class);

        LambdaQueryWrapper<ArticleTag> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ArticleTag::getArticleId,article.getId());
        List<ArticleTag> tagList = articleTagService.list(lambdaQueryWrapper);
        List<String> tags = tagList.stream().map(articleTag -> Long.toString(articleTag.getTagId()))
                .collect(Collectors.toList());
        adminArticleVo.setTags(tags);

        return GlobalResponse.ok(adminArticleVo);
    }

    @Override
    public GlobalResponse<?> updateArticle(AddArticleDto articleDto) {
        Article article = BeanCopyUtils.copyBean(articleDto, Article.class);
        updateById(article);

        List<Long> tags = articleDto.getTags();

        List<ArticleTag> articleTag = tags.stream()
                .map(tagId -> new ArticleTag(article.getId(), tagId))
                .collect(Collectors.toList());


        //先删除article对应的标签，然后重新插入
        LambdaQueryWrapper<ArticleTag> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ArticleTag::getArticleId,article.getId());
        articleTagService.remove(lambdaQueryWrapper);
        articleTagService.saveBatch(articleTag);
        return GlobalResponse.ok();
    }
}
